#include "NewGame.h"

// Dialog constructor
NewGameDlg::NewGameDlg()
{
	// Dialog setup
	CtrlLayout(*this, "New game");
	speedSlider.MinMax(minSpeed, maxSpeed);
	speedSlider.Step(10);
	speedSlider.SetData(maxSpeed / 2);
	maxHungSlider.MinMax(minMaxHunger, maxMaxHunger);
	maxHungSlider.Step(10);
	maxHungSlider.SetData(maxMaxHunger / 2);
	prodSlider.MinMax(Person::minProductivity, Person::maxProductivity);
	prodSlider.Step(1);
	prodSlider.SetData(Person::maxProductivity / 2);
	appetSlider.MinMax(Person::minAppetite, Person::maxAppetite);
	appetSlider.Step(1);
	appetSlider.SetData(Person::maxAppetite / 2);
	algoSwitch.Set(0, 0);
	algoSwitch.Set(1, 1);
	algoSwitch.Set(2, 2);
	algoSwitch = 0;
	phList.Columns(1);
	// Connecting event handlers
	WhenClose = THISBACK(OnCancel);
	cancelBtn <<= THISBACK(OnCancel);
	startBtn <<= THISBACK(OnStart);
	addBtn <<= THISBACK(OnAdd);
	delBtn <<= THISBACK(OnRemove);
	applyBtn <<= THISBACK(OnApply);
	undoBtn <<= THISBACK(OnDiscard);
	phList.WhenSel = THISBACK(OnSelect);
	browseBtn <<= THISBACK(OnBrowse);
}

// Linking to the main window
void NewGameDlg::Link(int *_speed, int *_maxHung, bool *_stopDead, Array<Person> *_list, String *_logFile)
{
	speed = _speed;
	maxHung = _maxHung;
	stopDead = _stopDead;
	list = _list;
	logFile = _logFile;
	speedSlider.SetData(*speed);
	maxHungSlider.SetData(*maxHung);
	deadlockBtn = *stopDead;
	logBox = *logFile;
}

// Cancel new game creation
void NewGameDlg::OnCancel()
{
	*speed = speedSlider.GetData();
	*maxHung = maxHungSlider.GetData();
	*stopDead = deadlockBtn;
	Break(IDCANCEL);
	Close();
}

// Apply settings and get ready to start
void NewGameDlg::OnStart()
{
	*speed = speedSlider.GetData();
	*maxHung = maxHungSlider.GetData();
	*stopDead = deadlockBtn;
	if(logFile->IsEmpty())
	{
		Exclamation("You have to choose a file to write the log to!");
		return;
	}
	if(phList.GetCount() < 2)
	{
		Exclamation("At least 2 philosophers need to take part in modeling.");
		return;
	}
	Break(IDOK);
	Close();
}

// Adds a new philosopher to the list
void NewGameDlg::OnAdd()
{
	// Generating new unique name
	int i = 0, j;
	String name = "Philosopher ";
	String tmp;
	bool exists = true;
	while(exists)
	{
		exists = false;
		tmp = name + String(AsString(i));
		for(j = 0; j < list->GetCount(); j++)
			if((*list)[j].GetName() == tmp)
				exists = true;
		i++;
	}
	name = tmp;
	// Adding to the list
	list->Add(new Person(name, Person::maxProductivity/2, Person::maxAppetite/2, Voluntary, speed));
	phList.Add(name);
	phList.SetCursor(phList.GetCount() - 1);
}

// Removes selected philosopher from the list
void NewGameDlg::OnRemove()
{
	int pos = phList.GetCursor();
	if(pos < 0) return;
	String name = phList.Get(pos);
	int i = 0;
	for(i = 0; i < list->GetCount(); i++)
	{
		if((*list)[i].GetName() == name)
		{
			list->Remove(i);
			break;
		}
	}
	phList.Remove(pos);
}

// Updates the editor after a philosopher has been chosen
void NewGameDlg::OnSelect()
{
	int pos = phList.GetCursor();
	if(pos < 0) return;
	String name = phList.Get(pos);
	int i;
	Person *phil;
	for(i = 0; i < list->GetCount(); i++)
	{
		if((*list)[i].GetName() == name)
		{
			phil = &(*list)[i];
			break;
		}
	}
	nameBox = phil->GetName();
	prodSlider.SetData(phil->GetProductivity());
	appetSlider.SetData(phil->GetAppetite());
	switch(phil->GetAlgo())
	{
		case Simple:
			algoSwitch = 0;
			break;
		case Random:
			algoSwitch = 1;
			break;
		case Ordered:
			algoSwitch = 2;
			break;
		case Voluntary:
			algoSwitch = 3;
			break;
	}
}

// Applies changes made in editor
void NewGameDlg::OnApply()
{
	int pos = phList.GetCursor();
	if(pos < 0) return;
	String name = phList.Get(pos);
	int i;
	Person *phil;
	for(i = 0; i < list->GetCount(); i++)
	{
		if((*list)[i].GetName() == name)
		{
			phil = &(*list)[i];
			break;
		}
	}
	String input = String(nameBox.GetData());
	bool exists = false;
	if(input != name)
	{
		for(i = 0; i < list->GetCount(); i++)
		{
			if((*list)[i].GetName() == input)
			{
				exists = true;
				break;
			}
		}
	}
	if(exists)
		Exclamation("A philosopher with this name already exists. Choose a different name.");
	else
	{
		phil->SetName(input);
		phil->SetProductivity(prodSlider.GetData());
		phil->SetAppetite(appetSlider.GetData());
		switch(algoSwitch)
		{
			case 0:
				phil->SetAlgo(Simple);
				break;
			case 1:
				phil->SetAlgo(Random);
				break;
			case 2:
				phil->SetAlgo(Ordered);
				break;
			case 3:
				phil->SetAlgo(Voluntary);
				break;
		}
		if(input != name)
		{
			phList.Remove(pos);
			phList.Insert(pos, input);
			phList.SetCursor(pos);
		}
	}
}

// Discards editor changes
void NewGameDlg::OnDiscard()
{
	OnSelect();
}

// Log file selection dialog
void NewGameDlg::OnBrowse()
{
	FileSel fs;
	fs.Type("Text files", "*.txt *.log");
	fs.AllFilesType();
	fs.DefaultExt("log");
	if(!logFile->IsEmpty())
		fs.Set(*logFile);
	if(fs.ExecuteSaveAs("Log output file"))
	{
		*logFile = fs.Get();
		logBox = *logFile;
	}
	else
		Exclamation("You should choose a file accessible for writing.");
}
